//
// Created by ta&to on 2022/8/23.
//
#include "http_log.h"

#define ACCESS_FILE "./logs/access.out"
#define ERROR_FILE  "./logs/error.out"

static file_n file;
static http_str_t err_levels[] = {
        http_null_string,
        http_string("critical"),
        http_string("error"),
        http_string("warning"),
        http_string("info"),
        http_string("debug")
};
/*
 * 创建一个日志任务容器
 */
static inline log_task_t *newlogcontainer(char* logstr, struct file_s *file, int err)
{
    log_task_t *ltt;
    ltt = (log_task_t *)http_calloc(sizeof(log_task_t));
    ltt->data = dtsnew(logstr);
    ltt->file = file;
    ltt->err  = err;
}
/*
 * 销毁一个日志任务容器
 */
static inline void destrylogcontainer(log_task_t *ltt)
{
    if(ISNULL(ltt)) return;
    dtsfree(ltt->data);
    http_free(ltt);
}
// 插入日志
static inline void log_push(struct Queue *ltq, char* logstr, file_n *handler, int err)
{
    if(ISNULL(ltq) || ISNULL(logstr))
        return;
    log_task_t *ltt = newlogcontainer(logstr, handler, err);
    push_task_block(ltq, ltt);
}
// 取出日志
static inline log_task_t* log_pop(struct Queue *ltq)
{
    if(ISNULL(ltq)) return NULL;
    return pop_task_block(ltq);
}
// 日志处理中心
void log_write_core(int level, int err, log_t *logs,char *fmt, ...)
{
    va_list      args;
    char *p, *last, *msg;
    char errstr[MAX_ERROR_STR];
    memset(errstr, 0, MAX_ERROR_STR);
    last = errstr + MAX_ERROR_STR;
    http_time_update(); // 更新时间
    p = http_cpymem(errstr, http_cached_err_log_time.data, http_cached_err_log_time.len);
    p = http_slprintf(p, last, " [%V] ", &err_levels[level]);

    msg = p;

    va_start(args, fmt);
    p = http_vslprintf(p, last, fmt, args);
    va_end(args);
    if (level != LOG_DEBUG && logs->handler) {
        p = logs->handler(logs, p, last - p);
    }

    if (p > last - HTTP_LINEFEED_SIZE) {
        p = last - HTTP_LINEFEED_SIZE;
    }
    http_linefeed(p);

    msg -= (http_cached_err_log_time.len + err_levels[level].len + 4);

    log_push(&logs->task_queue, msg, err?logs->err_file:logs->debug_file, err);
}
void http_log_cycle(void *args, thread_task_args_t *args_t)
{
    log_t *logt = (log_t *)args;
    for (;;)
    {
        log_task_t *ltt = log_pop(&logt->task_queue);// 取出一个日志任务
        if(ISNULL(ltt)) continue;
        dts data = ltt->data;
        http_write_file(ltt->file, data, dtslen(data), -1);
        http_write_console((ltt->err?http_stderr:http_stdout), data, dtslen(data));
        destrylogcontainer(ltt);
    }
}

void log_init(log_t *logs)
{
    logs->handler = NULL;
    http_time_init();
    file_n *errfile, *debugfile;
    errfile = (file_n *) http_calloc(sizeof(struct file_s));
    debugfile = (file_n *) http_calloc(sizeof(struct file_s));
    errfile->fd = wfile(ERROR_FILE);
    logs->err_file = errfile;
    debugfile->fd =  wfile(ACCESS_FILE);
    logs->debug_file = debugfile;
    initQueue(&logs->task_queue, -1);
}